# _*_ coding: utf-8 _*_
from odoo import models, api, fields, _, SUPERUSER_ID
import odoo.addons.decimal_precision as dp
from odoo.exceptions import ValidationError, Warning
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT


class PurchaseRequestOrderLine(models.Model):
    _inherit = "stock.view.quant.mixin"
    _name = "purchase.request.order.line"

    order_id = fields.Many2one("purchase.request.order", string="Request Order")
    supplier_id = fields.Many2one("res.partner", related="order_id.supplier_id", string="Supplier")
    incoterm = fields.Many2one('stock.incoterms', related="order_id.incoterm", string='Incoterms')
    payment_term_id = fields.Many2one('account.payment.term', related="order_id.payment_term_id", string='Payment Terms')
    requisition_line_id = fields.Many2one("purchase.requisition.line",
                                          string="purchase Requisition Line")
    requisition_id = fields.Many2one("purchase.requisition", related="requisition_line_id.requisition_id",
                                     string="Requisition", store=True, readonly=True)
    recommendation = fields.Boolean('Recommendation')
    product_id = fields.Many2one("product.product", string="Product")
    product_uom_id = fields.Many2one("product.uom", string="UOM")
    product_qty = fields.Float(string="Product Quantity", digits=dp.get_precision('Product Unit of Measure'))
    delivery_date = fields.Date(string="Delivery Date", required=True)
    price_unit = fields.Float(string='Purchase Unit Price', required=True, digits=dp.get_precision('Product Price'))
    currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True)
    taxes_id = fields.Many2many('account.tax', string='Taxes',
                                domain=[('type_tax_use', '=', 'purchase')])

    price_subtotal = fields.Float(compute='_compute_amount', string='Subtotal', store=True)
    price_total = fields.Float(compute='_compute_amount', string='Total', store=True)
    price_tax = fields.Float(compute='_compute_amount', string='Tax', store=True)

    default_currency_id = fields.Many2one("res.currency", default=lambda self: self.env.user.company_id.currency_id,
                                          readonly=True)
    price_unit_default_currency = fields.Float(string='Unit Price Default Currency', required=True,
                                               digits=dp.get_precision('Product Price'),
                                               compute='_compute_amount')
    price_subtotal_default_currency = fields.Float(compute='_compute_default_currency',
                                                      string='Subtotal Default Currency', store=True)
    price_total_default_currency = fields.Float(compute='_compute_default_currency',
                                                   string='Total Default Currency', store=True)
    price_tax_default_currency = fields.Float(compute='_compute_default_currency',
                                                 string='Tax Default Currency', store=True)
    freight_currency_id = fields.Many2one("res.currency", string="Freight Currency")
    other_currency_id = fields.Many2one("res.currency", string="Other Currency")
    freight_price = fields.Float(string='Freight Price')
    other_price = fields.Float(string='Other Price')
    customers_amount = fields.Float(string='Customers Amount')
    freight_price_default_currency = fields.Float(compute='_compute_freight_amount',
                                                     string='Freight Price Default Currency',
                                                     store=True)
    other_price_default_currency = fields.Float(compute='_compute_freight_amount',
                                                   string='Other Price Default Currency',
                                                   store=True)
    line_subtotal_default_currency = fields.Float('Line Subtotal Default Currency',
                                                     readonly=True,
                                                     compute='_compute_freight_amount',
                                                     store=True)
    origin_price_unit = fields.Float('Price Unit', digits=dp.get_precision('Product Price'))
    price_unit_excluded = fields.Float(string='Price Unit Excluded Taxes', compute='_compute_amount', digits=dp.get_precision('Product Price'), default = 0.0)
    note = fields.Text(string="Note")
    department_id = fields.Many2one("hr.department", string="Department")
    user_id = fields.Many2one("res.users", string="User")
    state = fields.Selection([
        ('draft', 'Draft'),
        ("purchase_requesting", "Purchase Requesting"),
        ("price_comparing", "Price Comparing"),
        ("allow_purchase", "Allow Purchase"),
        ("already_purchase", "Already Purchase"),
        ("close", "Close"),
        ("cancel", "Cancel"),
    ], string="State", default="draft", readonly=True)
    safety_stock_qty = fields.Float(string='Safety Stock Quantity',
                                    related='product_id.safety_stock_qty',
                                    digits=dp.get_precision('Product Unit of Measure'),
                                    readonly=True)
    qty_available = fields.Float(string='Quantity On Hand',
                                 related='product_id.qty_available',
                                 digits=dp.get_precision('Product Unit of Measure'),
                                 readonly=True)
    virtual_available = fields.Float(string='Forecast Quantity',
                                     related='product_id.virtual_available',
                                     digits=dp.get_precision('Product Unit of Measure'),
                                     readonly=True)
    requisition_memo = fields.Text("Requisition Memo")
    product_code = fields.Char('Product Code')
    product_name = fields.Char('Product Name')
    name = fields.Char('Name')

    procurement_id = fields.Many2one('procurement.order', string='Procurement', ondelete='set null', copy=False)

    last_purchase_price = fields.Float('Last Purchase Price Unit', digits=dp.get_precision('Product Price'), compute="_compute_last_price")

    def _compute_last_price(self):
        for pr_line in self:
            po_lines = self.env['purchase.order.line'].search([('product_id', '=', pr_line.product_id.id),
                                                               ('partner_id', '=', pr_line.order_id.supplier_id.id),
                                                               ('state', 'in', ('purchase', 'done'))])
            if len(po_lines) > 0:
                line = sorted(po_lines, key=lambda x: x.order_id, reverse=True)[0]
                pr_line.last_purchase_price = line.price_unit

    @api.onchange("product_id")
    def _onchange_product_id(self):
        self.ensure_one()
        res = {}

        self.product_uom_id = self.product_id.uom_id
        fpos = self.order_id.fiscal_position_id
        if self.env.uid == SUPERUSER_ID:
            company_id = self.env.user.company_id.id
            self.taxes_id = fpos.map_tax(self.product_id.supplier_taxes_id.filtered(lambda r: r.company_id.id == company_id))
        else:
            self.taxes_id = fpos.map_tax(self.product_id.supplier_taxes_id)
        self._onchange_quantity()

        return res

    # @api.multi
    # def create(self, vals):
    #     res = super(PurchaseRequestOrderLine, self).create(vals)
    #     self._compute_amount()
    #     return res

    @api.multi
    def name_get(self):
        res = []
        for prl in self:
            res.append((prl.id, prl.order_id.name))
        return res

    @api.depends('product_qty', 'price_unit', 'taxes_id', "currency_id")
    def _compute_amount(self):
        default_currency = self.env.user.company_id.currency_id
        for line in self:
            taxes = line.taxes_id.compute_all(round(line.price_unit, 4), line.order_id.currency_id, line.product_qty,
                                              product=line.product_id, partner=line.order_id.supplier_id)
            price_unit_excluded = 0.0
            if line.product_qty != 0:
                price_unit_excluded = round(taxes['total_excluded']/line.product_qty, 4)
            line.update({
                'price_tax': taxes['total_included'] - taxes['total_excluded'],
                'price_total': taxes['total_included'],
                'price_subtotal': taxes['total_excluded'],
                'price_unit_excluded': price_unit_excluded,
                "price_unit_default_currency": line.currency_id.compute(line["price_unit"], default_currency),
            })

    @api.depends('price_tax', 'price_total', "price_subtotal", 'currency_id')
    def _compute_default_currency(self):
        default_currency = self.env.user.company_id.currency_id
        for line in self:
            line.update({
                "price_tax_default_currency": line.currency_id.compute(line["price_tax"], default_currency),
                "price_total_default_currency": line.currency_id.compute(line["price_total"], default_currency),
                "price_subtotal_default_currency": line.currency_id.compute(line["price_subtotal"], default_currency),

            })

    @api.depends('freight_price', 'other_price', 'freight_currency_id', 'other_currency_id', 'price_total', 'customers_amount')
    def _compute_freight_amount(self):
        default_currency = self.env.user.company_id.currency_id
        for line in self:
            subtotal = line.freight_currency_id.compute(line["freight_price"], default_currency) + \
                       line.other_currency_id.compute(line["other_price"], default_currency) + \
                       line.currency_id.compute(line["price_total"], default_currency) + \
                       line.customers_amount
            line.update({
                "freight_price_default_currency": line.freight_currency_id.compute(line["freight_price"], default_currency),
                "other_price_default_currency": line.other_currency_id.compute(line["other_price"], default_currency),
                "line_subtotal_default_currency": subtotal

            })

    # @api.depends('freight_price_default_currency', 'other_price_default_currency', 'customers_amount', 'price_subtotal_default_currency')
    # def _compute_line_subtotal(self):
    #     for line in self:
    #         subtotal = line.freight_price_default_currency or 0 + line.other_price_default_currency or 0\
    #                    + line.customers_amount or 0 + line.price_subtotal_default_currency or 0
    #         line.update({
    #             'line_subtotal_default_currency': subtotal
    #         })

    @api.onchange('product_qty', 'product_uom')
    def _onchange_quantity(self):
        if not self.product_id:
            return

        seller = self.product_id._select_seller(
            partner_id=self.supplier_id,
            quantity=self.product_qty,
            date=self.order_id.date and self.order_id.date[:10],
            uom_id=self.product_uom_id)

        if not seller:
            return

        price_unit = self.env['account.tax']._fix_tax_included_price(seller.price, self.product_id.supplier_taxes_id, self.taxes_id) if seller else 0.0
        if price_unit and seller and self.order_id.currency_id and seller.currency_id != self.order_id.currency_id:
            price_unit = seller.currency_id.compute(price_unit, self.order_id.currency_id)

        if seller and self.product_uom_id and seller.product_uom != self.product_uom_id:
            price_unit = seller.product_uom_id._compute_price(price_unit, self.product_uom_id)

        self.price_unit = price_unit
        self.origin_price_unit = price_unit
        self.product_code = seller.product_code
        self.product_name = seller.product_name

    @api.model
    def check_request_sum_qty_gt_requisition_qty(self):
        for pr_line in self:
            # sum the product in all request's qty
            request_sum = sum(self.env['purchase.request.order.line'].
                              search([('requisition_line_id', '=', pr_line.requisition_line_id.id)]).
                              filtered(lambda p: p.state in ('already_purchase', 'close', 'allow_purchase')).
                              mapped('product_qty'))
            # check request sum qty gt requisition qty
            if request_sum + pr_line.product_qty > pr_line.requisition_line_id.product_qty:
                return True
            return False

    def action_allow_purchase(self):
        if self.check_request_sum_qty_gt_requisition_qty():
            raise Warning(_("Request qty can't greater than requisition qty"))
        self.write({
            "state": "allow_purchase"
        })
        if len(self.order_id.line_ids.filtered(lambda l: l.state not in ('draft', 'purchase_requesting', 'price_comparing'))) == len(self.order_id.line_ids):
            self.order_id.write({
                "state": "allow_purchase"
            })

        if self.requisition_id and self.requisition_line_id:
            other_pr_lines = self.search([('requisition_id', '=', self.requisition_id.id),
                                          ('requisition_line_id', '=', self.requisition_line_id.id)]).filtered(lambda p: p.id != self.id and p.state not in ('already_purchase', 'allow_purchase'))
            # Modify For REQ308
            request_sum = sum(self.env['purchase.request.order.line'].
                              search([('requisition_line_id', '=', self.requisition_line_id.id)]).
                              filtered(lambda p: p.state in ('already_purchase', 'close', 'allow_purchase')).
                              mapped('product_qty'))
            if request_sum > self.requisition_line_id.product_qty:
                raise Warning('允许采购加已采购数量超出请购数量')
            if request_sum == self.requisition_line_id.product_qty:
                self.requisition_line_id.state = 'done'
                for line in other_pr_lines:
                    # REQ342, ignore to cancel pr.
                    # line.order_id.action_cancel()
                    line.action_cancel()
        return {'type': 'ir.actions.client', 'tag': 'reload_view'}

    def action_cancel(self):
        self.write({
            "state": "cancel"
        })

    @api.multi
    def action_approve(self):
        if self.state != 'purchase_requesting':
            raise Warning(u'只有状态为采购询价中时才允许提交!')
        for pr in self:
            pr.write({
                "state": "price_comparing"
            })

            # if len(pr.order_id.line_ids.filtered(lambda l: l.state not in ('draft', 'purchase_requesting'))) == len(pr.order_id.line_ids):
            #     pr.order_id.write({
            #         "state": "price_comparing"
            #     })
            # for line in pr.order_id.line_ids:
            #     sum_qty = sum(line.search([('requisition_line_id', '=', line.requisition_line_id.id)]).\
            #                   filtered(lambda r: r.state not in ('draft', 'purchase_requesting', 'cancel')).\
            #                   mapped('product_qty'))
                # if sum_qty >= line.requisition_line_id.product_qty:
                #     line.requisition_line_id.write({'state': 'done'})

    def action_recommend(self):
        for order in self:
            if order.state in ['draft', 'purchase_requesting', 'price_comparing']:
                order.write({
                    "recommendation": True
                })

    def action_unrecommend(self):
        for order in self:
            if order.state in ['draft', 'purchase_requesting', 'price_comparing']:
                order.write({
                    "recommendation": False
                })

    @api.multi
    def action_view_quants_by_item(self):
        return self.action_view_quant_by_product_ids([self.product_id.id])

    @api.multi
    def action_create_purchase_order_by_line(self):
        # if len(self.mapped('supplier_id')) > 1:
        #     raise ValidationError(u'只允许合并相同的供应商')
        # if len(self.mapped('order_id.user_id')) > 1:
        #     raise ValidationError(u'只允许合并相同的采购人员')
        # if len(self.mapped('order_id.currency_id')) > 1:
        #     raise ValidationError(u'只允许合并相同的币种')
        # if len(self.mapped('order_id.payment_term_id')) > 1:
        #     raise ValidationError(u'只允许合并相同的付款条件')
        # if len(self.mapped('order_id.incoterm')) > 1:
        #     raise ValidationError(u'只允许合并相同的贸易术语')
        if not self.filtered(lambda l: l.state == "allow_purchase"):
            raise ValidationError(_("There is no allow purchase line."))
        PurchaseOrder = self.env["purchase.order"]

        for supplier_id in self.mapped('supplier_id'):
            for user_id in self.mapped('order_id.user_id'):
                for currency_id in self.mapped('order_id.currency_id') and self.mapped('order_id.currency_id') or [False]:
                    for payment_term_id in self.mapped('order_id.payment_term_id') and self.mapped('order_id.payment_term_id') or [False]:
                        for incoterm in self.mapped('order_id.incoterm') and self.mapped('order_id.incoterm') or [False]:
                            purchase_order = PurchaseOrder.search([
                                ("partner_id", "=", supplier_id.id),
                                ("user_id", "=", user_id.id),
                                ("currency_id", "=", currency_id and currency_id.id or False),
                                ("payment_term_id", "=", payment_term_id and payment_term_id.id or False),
                                ("incoterm_id", "=", incoterm and incoterm.id or False),
                                ("state", "=", "draft")
                            ])

                            pr_order_lines = self.filtered(
                                lambda l: l.supplier_id.id == supplier_id.id and
                                l.order_id.user_id.id == user_id.id and
                                l.order_id.currency_id.id == (currency_id and currency_id.id or False) and
                                l.order_id.payment_term_id.id == (payment_term_id and payment_term_id.id or False) and
                                l.order_id.incoterm.id == (incoterm and incoterm.id or False)
                            )

                            for pr_order_line in pr_order_lines:

                                line_vals = []
                                for line in pr_order_line:
                                    if line.state != "allow_purchase":
                                        continue
                                    line_vals.append((0, 0, {
                                        "name": line.product_id.name,
                                        "product_id": line.product_id.id,
                                        "product_uom": line.product_uom_id.id,
                                        "date_planned": line.delivery_date,
                                        "product_qty": line.product_qty,
                                        "price_unit": line.price_unit,
                                        "note": line.note,
                                        "taxes_id": [(6, 0, line.taxes_id.ids)],
                                        "requisition_memo": line.requisition_memo,
                                        "pr_line_id": line.id,
                                        "product_code": line.order_id._compute_product_code(line),
                                        "product_name": line.order_id._compute_product_name(line)
                                    }))
                                if purchase_order:
                                    vals = {
                                        "order_line": line_vals
                                    }
                                    purchase_order[0].write(vals)
                                else:
                                    vals = {
                                        "partner_id": supplier_id.id,
                                        "user_id": user_id.id,
                                        "currency_id": currency_id and currency_id.id or False,
                                        "payment_term_id": payment_term_id and payment_term_id.id or False,
                                        "incoterm_id": incoterm and incoterm.id or False,
                                        "order_line": line_vals,
                                        "pr_id": pr_order_line[0].order_id.id
                                    }
                                    purchase_order = PurchaseOrder.create(vals)
                                for line in pr_order_line:
                                    if line.state != "allow_purchase":
                                        continue
                                    line.write({
                                        "state": "already_purchase"
                                    })
                                pr_order_line[0].order_id.write({
                                    "po_id": purchase_order.id
                                })
                                pr_line = self.env['purchase.order.line'].search([('pr_line_id', '=', line_vals[0][2]['pr_line_id']), ('order_id', '=', purchase_order.id)])
                                pr_order_line[0].requisition_id.procurement_id.write({
                                    "purchase_line_id": pr_line.id
                                })
                                if purchase_order.origin and pr_order_line[0].order_id.name not in purchase_order.origin:
                                    purchase_order.origin += "," + pr_order_line[0].order_id.name
                                else:
                                    purchase_order.origin = pr_order_line[0].order_id.name
        return {'type': 'ir.actions.client', 'tag': 'reload_view'}

    @api.multi
    def action_query_po_history(self):
        ir_model_data = self.env['ir.model.data']
        try:
            compose_form_id = ir_model_data.get_object_reference('purchase_order_extend', 'ol_purchase_order_history')[1]
        except ValueError:
            compose_form_id = False
        ctx = dict()
        ctx.update({
            'default_model': 'purchase.order.line',
        })
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'tree',
            'view_mode': 'tree',
            'res_model': 'purchase.order.line',
            'views': [(compose_form_id, 'tree')],
            'view_id': compose_form_id,
            'target': 'new',
            'context': ctx,
            'domain': [('product_id', '=', self.product_id.id)]
        }

    @api.multi
    def _compute_tax_id(self):
        for line in self:
            fpos = line.order_id.fiscal_position_id or line.order_id.supplier_id.property_account_position_id
            # If company_id is set, always filter taxes by the company
            taxes = line.product_id.supplier_taxes_id.filtered(lambda r: not line.order_id.company_id or r.company_id == line.order_id.company_id)
            line.taxes_id = fpos.map_tax(taxes, line.product_id, line.order_id.supplier_id) if fpos else taxes
